home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Applications / Eudora 1.3.1 / source / mailbox.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-16  |  32.0 KB  |  1,236 lines  |  [TEXT/MPS ]

  1. #define FILE_NUM 21
  2. #pragma load EUDORA_LOAD
  3. #pragma segment Mailbox
  4.  
  5.     int OpenMailbox(long dirId,UPtr name, Boolean showIt);
  6.     void SwapSum(MSumPtr sum1, MSumPtr sum2);
  7.     void ZeroMailbox(TOCHandle tocH);
  8.     void AddBox(short menuId,short function,UPtr name,Boolean folder,short level);
  9. static Str31 Re;
  10.     void AddBoxCountItem(short item,long dirId);
  11.     void AddBoxCountMenu(MenuHandle mh, short item, long dirId);
  12.     Boolean WantRebuildTOC(UPtr boxName);
  13.     Boolean InsaneTOC(TOCHandle tocH);
  14.     void NoteFreeSpace(TOCHandle tocH);
  15.  
  16. /************************************************************************
  17.  * TOCByName - take a mailbox name, return a TOC
  18.  ************************************************************************/
  19. TOCHandle TOCByName(long dirId,UPtr name)
  20. {
  21.     if (!GetMailbox(dirId,name,False)) return(FindTOC(dirId,name));
  22.     return(nil);
  23. }
  24.  
  25. /**********************************************************************
  26.  * GetMailbox - put a mailbox window frontmost; open if necessary
  27.  **********************************************************************/
  28. int GetMailbox(long dirId,UPtr name,Boolean showIt)
  29. {
  30.     TOCHandle toc;
  31.     
  32.     if (toc=FindTOC(dirId,name))
  33.     {
  34.         UsingWindow((*toc)->win);
  35.         if (showIt)
  36.         {
  37.             if (!((WindowPeek)(*toc)->win)->visible)
  38.                 ShowMyWindow((*toc)->win);
  39.             SelectWindow((*toc)->win);
  40.         }
  41.         return(0);
  42.     }
  43.     
  44.     return(OpenMailbox(dirId,name,showIt));
  45. }
  46.  
  47. /**********************************************************************
  48.  * OpenMailbox - open the named mailbox
  49.  **********************************************************************/
  50. int OpenMailbox(long dirId,UPtr name, Boolean showIt)
  51. {
  52.  
  53.     TOCHandle toc;
  54.     MyWindow *win;
  55.     
  56.     /*
  57.      * create window
  58.      */
  59.     if ((win=GetNewMyWindow(MAILBOX_WIND,nil,InFront,True,True))==nil)
  60.     {
  61.         WarnUser(COULDNT_WIN,MemError());
  62.         return(MemError());
  63.     }
  64.  
  65.     win->hPitch = FontWidth;
  66.     win->vPitch = FontLead+FontDescent;
  67.     
  68.     /*
  69.      * read or build toc for window
  70.      */
  71.     toc = CheckTOC(dirId,name);
  72.     if (toc==nil)
  73.     {
  74.         DisposeWindow(win);
  75.         return(1);
  76.     }
  77.     
  78.     /*
  79.      * set it up properly
  80.      */
  81.     ((WindowPeek)win)->windowKind = (*toc)->which==OUT ? CBOX_WIN : MBOX_WIN;
  82.     ((WindowPeek)win)->refCon = (long) toc;
  83.     win->close = BoxClose;
  84.     win->click = BoxClick;
  85.     win->activate = BoxActivate;
  86.     win->menu = BoxMenu;
  87.     win->key = BoxKey;
  88.     win->help = BoxHelp;
  89.     win->didResize = BoxDidResize;
  90.     win->gonnaShow = BoxGonnaShow;
  91.     win->position = BoxPosition;
  92.     win->cursor = BoxCursor;
  93.     win->zoomSize = MaxSizeZoom;
  94.     win->minSize.h = 2*GetRLong(BOX_SIZE_SIZE);
  95.     
  96.     (*toc)->win = win;
  97.     ((WindowPeek)win)->windowKind = (*toc)->which==OUT ? CBOX_WIN : MBOX_WIN;
  98.     SetWTitle(win,name);
  99.     if (showIt)
  100.         ShowMyWindow(win);
  101.     
  102.     /*
  103.      * push it onto list of open toc's
  104.      */
  105.     LL_Push(TOCList,toc);
  106.     
  107.     return(0);
  108. }
  109.  
  110. /**********************************************************************
  111.  * SaveMessageSum - save a message summary into a TOC
  112.  **********************************************************************/
  113. Boolean SaveMessageSum(MSumPtr sum,TOCHandle tocH)
  114. {
  115.     if ((*tocH)->count)
  116.     {
  117.         SetHandleBig(tocH,GetHandleSize(tocH)+sizeof(MSumType));
  118.         if (MemError()) return (False);
  119.     }
  120.     (*tocH)->needRedo = (*tocH)->count;
  121.     BlockMove(sum,&(*tocH)->sums[(*tocH)->count++],sizeof(MSumType));
  122.     CalcSumLengths(tocH,(*tocH)->count-1);
  123.     InvalSum(tocH,(*tocH)->count-1);
  124.     (*tocH)->dirty = True;
  125.     return(True);
  126. }
  127.  
  128. /**********************************************************************
  129.  * CheckTOC - check a file for a table of contents, and build it if
  130.  * necessary.
  131.  **********************************************************************/
  132. TOCHandle CheckTOC(long dirId,UPtr boxName)
  133. {
  134.     Str31 tocName;
  135.     HFileInfo tocInfo,boxInfo;
  136.     int err;
  137.     Str15 suffix;
  138.     Boolean makeDirty=False;
  139.     TOCHandle ourBoy;
  140.     short res;
  141.     
  142.     /*
  143.      * toc is kept in name.toc; get info on it
  144.      */
  145.     BlockMove(boxName,tocName,*boxName+1L);
  146.     PCat(tocName,GetRString(suffix,TOC_SUFFIX));
  147.     if (err=HGetFileInfo(MyVRef,dirId,tocName,&tocInfo))
  148.         return (BuildTOC(dirId,boxName));
  149.     
  150.     /*
  151.      * now, info on the box
  152.      */
  153.     if (err=HGetFileInfo(MyVRef,dirId,boxName,&boxInfo))
  154.         return (nil);
  155.     
  156.     /*
  157.      * is toc older than box?
  158.      * the -5 is for slop; the filesystem seems to be a bit arbitrary about
  159.      * modify times
  160.      */
  161.     if (tocInfo.ioFlMdDat<boxInfo.ioFlMdDat-5 && !PrefIsSet(PREF_IGNORE_OUTDATE))
  162.     {
  163.         res = AlertStr(NEW_TOC_ALRT,Caution,boxName);
  164.         if (res==TOC_CREATE_NEW) return(ReBuildTOC(dirId,boxName));
  165.         else if (res==TOC_CANCEL) return(nil);
  166.         else makeDirty = True;
  167.     }
  168.     
  169.     /*
  170.      * try to read toc
  171.      */
  172.     ourBoy = ReadTOC(dirId,boxName);
  173.     if (ourBoy && makeDirty) (*ourBoy)->dirty = True;
  174.     return(ourBoy);
  175. }
  176.  
  177. /**********************************************************************
  178.  * ReadTOC - read the toc file for a mailbox
  179.  **********************************************************************/
  180. TOCHandle ReadTOC(long dirId,UPtr boxName)
  181. {
  182.     Str31 tocName,scratch;
  183.     long count;
  184.     int err;
  185.     short refN=0;
  186.     TOCHandle tocH;
  187.     Str15 suffix;
  188.     
  189.     /*
  190.      * toc is kept in name.toc; try to open it
  191.      */
  192.     BlockMove(boxName,tocName,*boxName+1L);
  193.     PCat(tocName,GetRString(suffix,TOC_SUFFIX));
  194.     if (err=FSHOpen(tocName,MyVRef,dirId,&refN,fsRdPerm)) goto failure;
  195.     
  196.     /*
  197.      * allocate space for the toc
  198.      */
  199.     err = GetEOF(refN, &count);
  200.     if (err) goto failure;
  201.     err = count < sizeof(TOCType);    /* change to support different toc versions */
  202.     if (err) goto failure;
  203.     tocH = NuHandle(count);
  204.     if (!tocH)
  205.     {
  206.         FSClose(refN);
  207.         WarnUser(MEM_ERR,MemError());
  208.         return(nil);
  209.     }
  210.     
  211.     /*
  212.      * try to read it
  213.      */
  214.     LDRef(tocH);
  215.     err = FSRead(refN,&count,*tocH);
  216.     (void) FSClose(refN), refN = 0;
  217.     if (err) goto failure;
  218.     
  219.     /*
  220.      * don't take these for granted...
  221.      */
  222.     (*tocH)->dirty = False;
  223.     (*tocH)->vRef = MyVRef;
  224.     (*tocH)->dirId = dirId;
  225.     (*tocH)->refN = 0;
  226.     (*tocH)->win = nil;
  227.     (*tocH)->volumeFree = 0;
  228.     
  229.     /*
  230.      * now, make sure the filename matches, for people who rename with the
  231.      * finder
  232.      */
  233.     PCopy((*tocH)->name,boxName);
  234.     
  235.     /*
  236.      * and make sure it hasn't become special or unspecial
  237.      */
  238.     (*tocH)->which = 0;
  239.     if (dirId==MyDirId)
  240.     {
  241.         if (EqualString(GetRString(scratch,IN),boxName,False,True))
  242.             (*tocH)->which = IN;
  243.         else if (EqualString(GetRString(scratch,OUT),boxName,False,True))
  244.             (*tocH)->which = OUT;
  245.         else if (EqualString(GetRString(scratch,TRASH),boxName,False,True))
  246.             (*tocH)->which = TRASH;
  247.     }
  248.  
  249.     /*
  250.      * check toc for reasonableness
  251.      */
  252.     if (InsaneTOC(tocH)) goto failure;
  253.     
  254.     /*
  255.      * make sure we don't have any leftovers
  256.      */
  257.     CleanseTOC(tocH);
  258.     
  259.     /*
  260.      * just to make sure...
  261.      */
  262.     if (dirId==MyDirId)
  263.     {
  264.         if (EqualString(boxName,GetRString(tocName,OUT),False,True))
  265.             (*tocH)->which = OUT;
  266.         else if (EqualString(boxName,GetRString(tocName,IN),False,True))
  267.             (*tocH)->which = IN;
  268.         else if (EqualString(boxName,GetRString(tocName,TRASH),False,True))
  269.             (*tocH)->which = TRASH;
  270.     }
  271.     
  272.     /*
  273.      * and sizes
  274.      */
  275.     GetTOCK(tocH,&(*tocH)->usedK,&(*tocH)->totalK);
  276.     
  277.     /*
  278.      * hurray for our side!
  279.      */
  280.     UL(tocH);
  281.     return(tocH);
  282.  
  283. failure:
  284.     if (refN) FSClose(refN);
  285.     if (tocH) ZapHandle(tocH);
  286.     if (err) FileSystemError(READ_TOC,boxName,err);
  287.     return (WantRebuildTOC(boxName)?ReBuildTOC(dirId,boxName):nil);
  288. }
  289.  
  290. /**********************************************************************
  291.  * WriteTOC - write a toc to the proper file
  292.  **********************************************************************/
  293. int WriteTOC(TOCHandle tocH)
  294. {
  295.     Str31 tocName;
  296.     Str15 suffix;
  297.     int err;
  298.     short refN=0;
  299.     long count;
  300.     
  301.     /*
  302.      * build the name
  303.      */
  304.     PCopy(tocName,(*tocH)->name);
  305.     PCat(tocName,GetRString(suffix,TOC_SUFFIX));
  306.     
  307.     /*
  308.      * open the file
  309.      */
  310.     err = FSHOpen(tocName,(*tocH)->vRef,(*tocH)->dirId,&refN,fsRdWrPerm);
  311.     if (err == fnfErr)
  312.     {
  313.         if (err=HCreate((*tocH)->vRef,(*tocH)->dirId,tocName,CREATOR,TOC_TYPE))
  314.             goto failure;
  315.         err = FSHOpen(tocName,(*tocH)->vRef,(*tocH)->dirId,&refN,fsRdWrPerm);
  316.     }
  317.     if (err) goto failure;
  318.         
  319.     
  320.     /*
  321.      * write the file
  322.      */
  323.     count = GetHandleSize(tocH);
  324.     if (err = FSWrite(refN,&count,*tocH)) goto failure;
  325.  
  326.     /*
  327.      * and sizes
  328.      */
  329.     GetTOCK(tocH,&(*tocH)->usedK,&(*tocH)->totalK);
  330.     
  331.     /*
  332.      * done
  333.      */
  334.     GetFPos(refN,&count);
  335.     SetEOF(refN,count);
  336.     (void) FSClose(refN);
  337.     (*tocH)->dirty = False;
  338.     ComposeLogS(LOG_FLOW,nil,"\pWriteTOC %p\n",tocName);
  339.     UL(tocH);
  340.     
  341.     /*
  342.      * the size area
  343.      */
  344.     if ((*tocH)->win&&(*tocH)->win->qWindow.visible)
  345.         InvalBoxSizeBox((*tocH)->win);
  346.         
  347.     return(noErr);
  348.     
  349. failure:
  350.     FileSystemError(WRITE_TOC,tocName,err);
  351.     UL(tocH);
  352.     if (refN)
  353.     { /* get rid of partial file */
  354.         (void) FSClose(refN);
  355.         (void) HDelete((*tocH)->vRef,(*tocH)->dirId,tocName);
  356.     }
  357.     return(err);
  358. }
  359.  
  360. /************************************************************************
  361.  * CalcAllSumLengths - calculate all the lengths for all the sums in a toc
  362.  ************************************************************************/
  363. void CalcAllSumLengths(TOCHandle toc)
  364. {
  365.     int sumNum;
  366.  
  367.     for (sumNum=0; sumNum<(*toc)->count; sumNum++)
  368.         CalcSumLengths(toc,sumNum);
  369. }
  370.  
  371. /************************************************************************
  372.  * CalcSumLengths - calculcate how long the strings in a sum can be
  373.  ************************************************************************/
  374. void CalcSumLengths(TOCHandle tocH,int sumNum)
  375. {
  376.     Str255 scratch;
  377.     short trunc;
  378.     short dWidth = (*BoxLines)[WID_DATE]-(*BoxLines)[WID_DATE-1];
  379.     short fWidth = (*BoxLines)[WID_FROM]-(*BoxLines)[WID_FROM-1];
  380.     
  381.     if (FontIsFixed)
  382.     {
  383.         (*tocH)->sums[sumNum].dateTrunc = dWidth/FontWidth - 1;
  384.         (*tocH)->sums[sumNum].fromTrunc = fWidth/FontWidth - 1;
  385.     }
  386.     else
  387.     {
  388.         PCopy(scratch,(*tocH)->sums[sumNum].date);
  389.         trunc = CalcTrunc(scratch,dWidth,InsurancePort);
  390.         if (trunc && trunc<*scratch) trunc--;
  391.         (*tocH)->sums[sumNum].dateTrunc = trunc;
  392.  
  393.         PCopy(scratch,(*tocH)->sums[sumNum].from);
  394.         trunc = CalcTrunc(scratch,fWidth,InsurancePort);
  395.         if (trunc && trunc<*scratch) trunc--;
  396.         (*tocH)->sums[sumNum].fromTrunc = trunc;
  397.     }
  398. }
  399.  
  400.  
  401. /**********************************************************************
  402.  * SetState - set a message's state in its summary.
  403.  **********************************************************************/
  404. void SetState(TOCHandle tocH,int sumNum,int state)
  405. {
  406.     int oldState = (*tocH)->sums[sumNum].state;
  407.         
  408.     if (oldState == state)
  409.         return;                                         /* nothing to do */
  410.  
  411.     InvalTocBox(tocH,sumNum,WID_STAT);
  412.     
  413.     if (oldState==QUEUED)
  414.       TimeStamp(tocH,sumNum,state==SENT ? GMTDateTime() : 0,ZoneSecs());
  415.     (*tocH)->sums[sumNum].state = state;
  416.     (*tocH)->dirty = True;
  417.     
  418. }
  419.  
  420. /**********************************************************************
  421.  * FindTOC - find a TOC in the TOC window list
  422.  **********************************************************************/
  423. TOCHandle FindTOC(long dirId,UPtr name)
  424. {
  425.     TOCHandle tocH;
  426.     
  427.     for (tocH=TOCList; tocH; tocH = (*tocH)->next)
  428.         if ((*tocH)->dirId==dirId && EqualString((*tocH)->name,name,False,True))
  429.             break;
  430.     return(tocH);
  431. }
  432.  
  433. /**********************************************************************
  434.  * BoxFOpen - open the mailbox file represented by a toc
  435.  * may be called on open mailbox, and reports error to user
  436.  **********************************************************************/
  437. int BoxFOpen(TOCHandle tocH)
  438. {
  439.     short refN;
  440.     int err=0;
  441.     Str31 name;
  442.     
  443.     if ((*tocH)->refN==0)
  444.     {
  445.         PCopy(name,(*tocH)->name);
  446.         err = FSHOpen(name,(*tocH)->vRef,(*tocH)->dirId,&refN,fsRdWrPerm);
  447.         if (err)
  448.             FileSystemError(OPEN_MBOX,(*tocH)->name,err);
  449.         else
  450.             (*tocH)->refN = refN;
  451.         ComposeLogS(LOG_FLOW,nil,"\pBoxFOpen %p\n",name);
  452.     }
  453.     
  454.     return(err);
  455. }
  456.  
  457. /**********************************************************************
  458.  * BoxFClose - close a mailbox file represented by a toc.  May be
  459.  * called on open mailbox, reports any errors to user.
  460.  **********************************************************************/
  461. int BoxFClose(TOCHandle tocH)
  462. {
  463.     int err=0;
  464.     
  465.     if ((*tocH)->refN)
  466.     {
  467.         NoteFreeSpace(tocH);
  468.         err = FSClose((*tocH)->refN);
  469.         (*tocH)->refN = 0;
  470.         if (err)
  471.             FileSystemError(CLOSE_MBOX,LDRef(tocH)->name,err);
  472.         ComposeLogS(LOG_FLOW,nil,"\pBoxFClose %p\n",LDRef(tocH)->name);
  473.         UL(tocH);
  474.     }
  475.     
  476.     return(err);
  477. }
  478.  
  479. /************************************************************************
  480.  * 
  481.  ************************************************************************/
  482. void NoteFreeSpace(TOCHandle tocH)
  483. {
  484.     short vRef;
  485.     long dirId;
  486.     Str31 name;
  487.     
  488.     if (GetFileByRef((*tocH)->refN,&vRef,&dirId,name))
  489.         (*tocH)->volumeFree = 0;
  490.     else
  491.         (*tocH)->volumeFree = VolumeFree(vRef);
  492. }
  493.  
  494. #pragma segment Main
  495. /**********************************************************************
  496.  * DeleteSum - remove a sum from a toc
  497.  **********************************************************************/
  498. void DeleteSum(TOCHandle tocH,int sumNum)
  499. {
  500.     MSumPtr sum;
  501.     int mNum;
  502.  
  503.     (*tocH)->maxValid = MIN((*tocH)->maxValid,sumNum-1);
  504.     if ((*tocH)->sums[sumNum].state==QUEUED) ForceSend = 0;
  505.     if (sumNum < (*tocH)->count-1)        /* is this not the last sum? */
  506.     {
  507.         LDRef(tocH);
  508.         sum = (*tocH)->sums + sumNum;
  509.         BlockMove(sum+1,sum,((*tocH)->count-1-sumNum)*sizeof(MSumType));
  510.         UL(tocH);
  511.         for (; mNum < (*tocH)->count-1; mNum++)
  512.             if ((MessType **)(*tocH)->sums[mNum].messH)
  513.                 (*(MessType **)(*tocH)->sums[mNum].messH)->sumNum--;
  514.     }
  515.     SetHandleBig(tocH,
  516.                         MAX(sizeof(TOCType),GetHandleSize(tocH)-sizeof(MSumType)));
  517.     if (--(*tocH)->count == 0) ZeroMailbox(tocH);
  518.  
  519.     (*tocH)->dirty = True;
  520. }
  521. #pragma segment Mailbox
  522.  
  523. /**********************************************************************
  524.  * InvalSum - invalidate an entire message summary line
  525.  **********************************************************************/
  526. void InvalSum(TOCHandle tocH,int sum)
  527. {
  528.     Rect r;
  529.     MyWindowPtr win = (*tocH)->win;
  530.     GrafPtr oldPort;
  531.     
  532.     if (!win) return;
  533.     GetPort(&oldPort);
  534.     SetPort(win);
  535.     
  536.     r.top = win->vPitch * (sum-GetCtlValue(win->vBar));
  537.     r.bottom = r.top + win->vPitch + 1;
  538.     r.left = win->contR.left;
  539.     r.right = win->contR.right;
  540.     InvalRect(&r);
  541.     SetPort(oldPort);
  542. }
  543.  
  544. /************************************************************************
  545.  *
  546.  ************************************************************************/
  547. void AddBox(short menuId,short function,UPtr name,Boolean folder,short level)
  548. {
  549.     MenuHandle mh=GetMHandle(menuId);
  550.     short base=function*MAX_BOX_LEVELS;
  551.     short item, lastItem;
  552.     Style theStyle;
  553.     Str31 scratch;
  554.     Boolean hasSub;
  555.     
  556.     lastItem=CountMItems(GetMHandle(menuId));
  557.     for (item=lastItem;item>0;item--)
  558.     {
  559.         hasSub=HasSubmenu(mh,item);
  560.         if (hasSub && !folder) continue;        /* add real mailboxes above folders */
  561.         GetItemStyle(mh,item,&theStyle);
  562.         if (theStyle) break;                                /* "new" is italicized */
  563.         MyGetItem(mh,item,scratch);
  564.         if (scratch[1]=='-') break;                 /* menu separator (transfer) */
  565.         if (IUCompString(scratch,name)<0) break;
  566.     }
  567.     MyInsMenuItem(GetMHandle(menuId),name,item);
  568.     if (folder)
  569.     {
  570.         AttachHierMenu(menuId,item+1,base+level);
  571.         InsertMenu(NewMenu(base+level,""),-1);
  572.         if (function==MAILBOX)
  573.             AppendMenu(GetMHandle(base+level),GetRString(scratch,NEW_ITEM_TEXT));
  574.     }
  575. }
  576.  
  577. /**********************************************************************
  578.  * GetNewMailbox - get the name of and create a new mailbox
  579.  * returns 1 for normal mb's, or else dirId
  580.  **********************************************************************/
  581. Boolean GetNewMailbox(long inDirId, UPtr name, Boolean *folder,long *newDirId,Boolean *xfer)
  582. {
  583.     DialogPtr dgPtr;
  584.     short item;
  585.     
  586.     ThirdCenterDialog(NEW_MAILBOX_DLOG);
  587.     if ((dgPtr = GetNewDialog(NEW_MAILBOX_DLOG,nil,InFront))==nil)
  588.     {
  589.         WarnUser(GENERAL,MemError());
  590.         return(False);
  591.     }
  592.     
  593.     if (!xfer) HideDItem(dgPtr,NEW_MAILBOX_NOXF);
  594.     ShowWindow(dgPtr);
  595.     HiliteButtonOne(dgPtr);
  596.     do
  597.     {
  598.         SelIText(dgPtr,NEW_MAILBOX_NAME,0,INFINITY);
  599.         PushCursor(iBeamCursor);
  600.         do
  601.         {
  602.             ModalDialog(DlgFilter,&item);
  603.             if (item==NEW_MAILBOX_FOLDER)
  604.                 SetDItemState(dgPtr,item,!GetDItemState(dgPtr,item));
  605.             else if (item==NEW_MAILBOX_NOXF)
  606.                 SetDItemState(dgPtr,item,!GetDItemState(dgPtr,item));
  607.         } while (item==NEW_MAILBOX_FOLDER || item==NEW_MAILBOX_NOXF);
  608.         PopCursor();
  609.         GetDIText(dgPtr,NEW_MAILBOX_NAME,name);
  610.         *folder = GetDItemState(dgPtr,NEW_MAILBOX_FOLDER);
  611.         if (xfer) *xfer = GetDItemState(dgPtr,NEW_MAILBOX_NOXF);
  612.     }
  613.     while (item==NEW_MAILBOX_OK && BadMailboxName(inDirId,name,*folder,newDirId));
  614.     
  615.     DisposDialog(dgPtr);
  616.     
  617.     return(item==NEW_MAILBOX_OK);
  618. }
  619.  
  620. /**********************************************************************
  621.  * RenameMailbox - rename a mailbox
  622.  **********************************************************************/
  623. int RenameMailbox(long inDirId,UPtr oldName, UPtr newName, Boolean folder)
  624. {
  625.     int err;
  626.     Str31 oldTOCName, newTOCName;
  627.     Str15 suffix;
  628.     
  629.     err = HRename(MyVRef,inDirId,oldName,newName);
  630.     if (err) return(FileSystemError(RENAMING_BOX,oldName,err));
  631.     
  632.     if (!folder)
  633.     {
  634.         PCopy(oldTOCName,oldName);
  635.         PCopy(newTOCName,newName);
  636.         PCat(oldTOCName,GetRString(suffix,TOC_SUFFIX));
  637.         PCat(newTOCName,GetRString(suffix,TOC_SUFFIX));
  638.         
  639.         err = HRename(MyVRef,inDirId,oldTOCName,newTOCName);
  640.         if (err==fnfErr) err = 0;
  641.         if (err)
  642.         {
  643.             FileSystemError(RENAMING_BOX,oldTOCName,err);
  644.             (void) HRename(MyVRef,inDirId,newName,oldName);
  645.         }
  646.     }
  647.     
  648.     return(err);
  649. }
  650.  
  651. /**********************************************************************
  652.  * BadMailboxName - figure out if a mailbox name is ok by trying to
  653.  * create the mailbox.
  654.  **********************************************************************/
  655. Boolean BadMailboxName(long inDirId,UPtr name,Boolean folder,long *newDirId)
  656. {
  657.     int err;
  658.     char *cp;
  659.     Str15 suffix;
  660.     
  661.     if (*name>31-*GetRString(suffix,TOC_SUFFIX))
  662.     {
  663.         TooLong(name);
  664.         return(True);
  665.     }
  666.     
  667.     if (name[1]=='.')
  668.     {
  669.         WarnUser(LEADING_PERIOD,0);
  670.         return(True);
  671.     }
  672.     
  673.     for (cp=name+*name;cp>name;cp--)
  674.         if (*cp==':')
  675.         {
  676.             WarnUser(NO_COLONS_HERE,0);
  677.             return(True);
  678.         }
  679.     
  680.     if (folder)
  681.     {
  682.         if (GetHandleSize(BoxMap)/sizeof(long)>MAX_BOX_LEVELS)
  683.         {
  684.             WarnUser(TOO_MANY_LEVELS,MAX_BOX_LEVELS);
  685.             return(True);
  686.         }
  687.         if (err=DirCreate(MyVRef,inDirId,name,newDirId))
  688.         {
  689.             FileSystemError(CREATING_MAILBOX,name,err);
  690.             return(True);
  691.         }
  692.         PtrAndHand(newDirId,BoxMap,sizeof(long));
  693.     }
  694.     else
  695.     {
  696.         err = HCreate(MyVRef,inDirId,name,CREATOR,MAILBOX_TYPE);
  697.         if (err)
  698.         {
  699.             FileSystemError(CREATING_MAILBOX,name,err);
  700.             return(True);
  701.         }
  702.     }
  703.     return(False);
  704. }
  705.  
  706. /************************************************************************
  707.  * ZeroMailbox - set a mailbox's size to zero.  Assumes box is empty
  708.  ************************************************************************/
  709. void ZeroMailbox(TOCHandle tocH)
  710. {
  711.     if (!BoxFOpen(tocH))
  712.     {
  713.         SetEOF((*tocH)->refN,0L);
  714.         BoxFClose(tocH);
  715.     }
  716. }
  717.  
  718. /************************************************************************
  719.  * FlushTOCs - make sure all toc's are quiescent
  720.  ************************************************************************/
  721. int FlushTOCs(Boolean andClose,Boolean canSkip)
  722. {
  723.     TOCHandle tocH, nextTocH;
  724.     int shdBe;
  725.     short err;
  726.     static long lastTime;
  727.     static short delay;
  728.     
  729.     if (canSkip && lastTime && TickCount()-lastTime < delay)
  730.         return(noErr);
  731.     
  732.     err = 0;
  733.     
  734.     for (tocH=TOCList; tocH; tocH = nextTocH)
  735.     {
  736.         if ((long)tocH < *(long *)ApplZone || (long)tocH > *(long *)HeapEnd ||
  737.              (long)*tocH < *(long *)ApplZone || (long)*tocH> *(long *)HeapEnd ||
  738.              (long)*tocH & 1)
  739.         {
  740. #ifdef DEBUG
  741.             if (RunType != Production) DebugStr("\pbad tocH!");
  742. #endif DEBUG
  743.             if (tocH==TOCList)
  744.                 TOCList = nil;
  745.             else
  746.             {
  747.                 for (nextTocH=TOCList;
  748.                          (*nextTocH)->next!=tocH;nextTocH=(*nextTocH)->next);
  749.                 (*nextTocH)->next = nil;
  750.             }
  751.             break;
  752.         }
  753.         
  754.         shdBe = sizeof(TOCType)+MAX(0,(*tocH)->count-1)*sizeof(MSumType);
  755.         if (GetHandleSize(tocH)!=shdBe)
  756.         {
  757. #ifdef DEBUG
  758.             if (RunType != Production)
  759.             {
  760.                 Str127 debug;
  761.                 Str32 name;
  762.                 PCopy(name,(*tocH)->name);
  763.                 ComposeString(debug,"\p%p: size %d, should be %d (%d + (%d-1)*%d)",
  764.                     name,GetHandleSize(tocH),shdBe,sizeof(TOCType),(*tocH)->count,
  765.                     sizeof(MSumType));
  766.                 SysBreakStr(debug);
  767.             }
  768. #endif DEBUG
  769.             SetHandleBig(tocH,shdBe);
  770.         }
  771.         nextTocH = (*tocH)->next;
  772.  
  773.         if (err=BoxFClose(tocH)) break;
  774.         if ((*tocH)->dirty)
  775.             if (err=WriteTOC(tocH))
  776.                 break;
  777.         if (andClose && !(*tocH)->win->qWindow.visible
  778.                 && !(MyNMRec && (*tocH)->which==IN))
  779.         {
  780.             int sNum;
  781.             for (sNum=0;sNum<(*tocH)->count;sNum++)
  782.                 if ((*tocH)->sums[sNum].messH) break;
  783.             if (sNum==(*tocH)->count)
  784.                 CloseMyWindow((*tocH)->win);
  785.         }
  786.         else RedoTOC(tocH);
  787.     }
  788.     
  789.     if (err)
  790.     {
  791.         lastTime = TickCount();
  792.         if (!delay)
  793.             delay = 60*30;
  794.         else
  795.             delay = MIN(60*60*5,(delay*3)/2);
  796.     }
  797.     else
  798.         lastTime = delay = 0;
  799.     return(err);
  800.  
  801. /************************************************************************
  802.  * SwapSum
  803.  ************************************************************************/
  804. void SwapSum(MSumPtr sum1, MSumPtr sum2)
  805. {
  806.     MSumType tempSum;
  807.     tempSum = *sum1;
  808.     *sum1 = *sum2;
  809.     *sum2 = tempSum;
  810. }
  811.  
  812. /************************************************************************
  813.  * SumTimeCompare - compare the arrival times of two sums
  814.  ************************************************************************/
  815. int SumTimeCompare(MSumPtr sum1, MSumPtr sum2)
  816. {
  817.     long res = (unsigned)sum1->seconds > (unsigned)sum2->seconds ? 1 :
  818.                          (sum1->seconds==sum2->seconds ? 0 : -1);
  819.     return(res ? res : sum1->spare[0]-sum2->spare[0]);
  820. }
  821.  
  822. /************************************************************************
  823.  * SumSubjCompare - compare the subjects of two sums
  824.  ************************************************************************/
  825. int SumSubjCompare(MSumPtr sum1, MSumPtr sum2)
  826. {
  827.     Str63 s1,s2;
  828.     Boolean p1,p2;
  829.     short result;
  830.     
  831.     PCopy(s1,sum1->subj);
  832.     PCopy(s2,sum2->subj);
  833.     p1 = TrimPrefix(s1,Re);
  834.     p2 = TrimPrefix(s2,Re);
  835.     TrimInitialWhite(s1);
  836.     TrimInitialWhite(s2);
  837.     result = IUCompString(s1,s2);
  838.     if (result) return(result);
  839.     if (p1)
  840.         return(p2?(sum1->spare[0]-sum2->spare[0]):1);
  841.     else
  842.         return((!p2)?(sum1->spare[0]-sum2->spare[0]):-1);
  843. }
  844.  
  845. /************************************************************************
  846.  * SumFromCompare - compare the senders of two sums
  847.  ************************************************************************/
  848. int SumFromCompare(MSumPtr sum1, MSumPtr sum2)
  849. {
  850.     short res=IUCompString(sum1->from,sum2->from);
  851.     return (res ? res : sum1->spare[0]-sum2->spare[0]);
  852. }
  853.  
  854.  
  855. /************************************************************************
  856.  * 
  857.  ************************************************************************/
  858. int SumStatCompare(MSumPtr sum1, MSumPtr sum2)
  859. {
  860.     short res = sum1->state-sum2->state;
  861.     return (res ? res : sum1->spare[0]-sum2->spare[0]);
  862. }
  863. int RevSumStatCompare(MSumPtr sum1, MSumPtr sum2)
  864. {
  865.     return(-SumStatCompare(sum1,sum2));
  866. }
  867. int SumPriorCompare(MSumPtr sum1, MSumPtr sum2)
  868. {
  869.     short p1,p2,res;
  870.     p1 = sum1->priority;
  871.     p2 = sum2->priority;
  872.     if (!p1) p1=Display2Prior(3);
  873.     if (!p2) p2=Display2Prior(3);
  874.     res = p1-p2;
  875.     return (res ? res : sum1->spare[0]-sum2->spare[0]);
  876. }
  877. int RevSumPriorCompare(MSumPtr sum1, MSumPtr sum2)
  878. {
  879.     return(-SumPriorCompare(sum1,sum2));
  880. }
  881.  
  882. int RevSumFromCompare(MSumPtr sum1, MSumPtr sum2)
  883. {return(-SumFromCompare(sum1,sum2));}
  884. int RevSumSubjCompare(MSumPtr sum1, MSumPtr sum2)
  885. {return(-SumSubjCompare(sum1,sum2));}
  886. int RevSumTimeCompare(MSumPtr sum1, MSumPtr sum2)
  887. {return(-SumTimeCompare(sum1,sum2));}
  888. /************************************************************************
  889.  * SortTOC - sort a toc, given a comparison function
  890.  ************************************************************************/
  891. void SortTOC(TOCHandle tocH, int (*compare)())
  892. {
  893.     MSumPtr sums, sPtr;
  894.     int count = (*tocH)->count;
  895.     Str63 infinity;
  896.     
  897.     SetHandleBig(tocH,GetHandleSize(tocH)+sizeof(MSumType));
  898.     if (MemError()) {WarnUser(MEM_ERR,MemError()); return;}
  899.     sums=LDRef(tocH)->sums;
  900.     GetRString(infinity,INFINITE_STRING);
  901.     PCopy(sums[count].from,infinity);
  902.     PCopy(sums[count].subj,infinity);
  903.     sums[count].seconds = 0xffffffff;
  904.     GetRString(Re,REPLY_INTRO);
  905.     
  906.     /* tag with original positions */
  907.     for (sPtr=sums;sPtr<sums+(*tocH)->count;sPtr++) sPtr->spare[0]=sPtr-sums;
  908.     
  909.     QuickSort(sums,sizeof(MSumType),0,count-1,compare,SwapSum);
  910.     for (sPtr=sums;sPtr<sums+(*tocH)->count;sPtr++)
  911.         if (sPtr->messH) (*(MessHandle)sPtr->messH)->sumNum = sPtr-sums;
  912.  
  913.     UL(tocH);
  914.     SetHandleBig(tocH,GetHandleSize(tocH)-sizeof(MSumType));
  915.     (*tocH)->dirty = True;
  916.     
  917.     if ((*tocH)->win)
  918.     {
  919.         GrafPtr oldPort;
  920.         GetPort(&oldPort); SetPort((*tocH)->win);
  921.         INVAL_RECT(&(*tocH)->win->contR);
  922.         SetPort(oldPort);
  923.         BoxCenterSelection((*tocH)->win);
  924.     }
  925. }
  926.  
  927. /************************************************************************
  928.  * GetInTOC - find the toc of the In mailbox
  929.  ************************************************************************/
  930. TOCHandle GetInTOC(void)
  931. {
  932.     Str31 inName;
  933.     
  934.     GetRString(inName,IN);
  935.     return(TOCByName(MyDirId,inName));
  936. }
  937.  
  938. /************************************************************************
  939.  * GetOutTOC - find the toc of the Out mailbox
  940.  ************************************************************************/
  941. TOCHandle GetOutTOC(void)
  942. {
  943.     Str31 outName;
  944.     
  945.     GetRString(outName,OUT);
  946.     return(TOCByName(MyDirId,outName));
  947. }
  948.  
  949. /************************************************************************
  950.  * RemoveMailbox - remove a mailbox
  951.  ************************************************************************/
  952. int RemoveMailbox(long inDirId,UPtr name)
  953. {
  954.     TOCHandle tocH;
  955.     int err;
  956.     Str31 delName;
  957.     Str15 suffix;
  958.     
  959.     /*
  960.      * open windows
  961.      */
  962.     if (tocH = FindTOC(inDirId,name))
  963.     {
  964.         (*tocH)->dirty = False;
  965.         if ((*tocH)->win) CloseMyWindow((*tocH)->win);
  966.     }
  967.  
  968.     /*
  969.      * files
  970.      */
  971.     PCopy(delName,name);
  972.     if (err = HDelete(MyVRef,inDirId,delName))
  973.         return(FileSystemError(DELETING_BOX,name,err));
  974.     PCat(delName,GetRString(suffix,TOC_SUFFIX));
  975.     err = HDelete(MyVRef,inDirId,delName);
  976.     if (err==fnfErr) err = 0;
  977.     if (err) return(FileSystemError(DELETING_BOX,delName,err));
  978.         
  979.     return(noErr);
  980. }
  981.  
  982. /************************************************************************
  983.  * MessagePosition - save/restore position for a new message window
  984.  ************************************************************************/
  985. Boolean MessagePosition(Boolean save,MyWindowPtr win)
  986. {
  987.     TOCHandle tocH = (*(MessHandle)win->qWindow.refCon)->tocH;
  988.     short sumNum = (*(MessHandle)win->qWindow.refCon)->sumNum;
  989.     Rect r;
  990.     Boolean zoomed;
  991.     Boolean res=True;
  992.     
  993.     if (save)
  994.     {
  995.         utl_SaveWindowPos(win,&r,&zoomed);
  996.         (*tocH)->sums[sumNum].savedPos = r;
  997.         if (zoomed)
  998.             (*tocH)->sums[sumNum].flags |= FLAG_ZOOMED;
  999.         else
  1000.             (*tocH)->sums[sumNum].flags &= ~FLAG_ZOOMED;
  1001.         (*tocH)->dirty = True;
  1002.     }
  1003.     else
  1004.     {
  1005.         r = (*tocH)->sums[sumNum].savedPos;
  1006.                 zoomed = false;
  1007.         if (r.right && r.right>r.left && r.bottom && r.bottom>r.top)
  1008.             zoomed = ((*tocH)->sums[sumNum].flags & FLAG_ZOOMED)!=0;
  1009.         else
  1010.         {
  1011.             short offset = GetMBarHeight();
  1012.             Point corner;
  1013.             short val;
  1014.             r = ((GrafPtr)win)->portRect;
  1015.             if (!(val=GetRLong(PREF_STRN+PREF_MWIDTH))) val=GetRLong(DEF_MWIDTH);
  1016.             r.right = r.left + win->hPitch*(val+1) + GROW_SIZE;
  1017.             if (val=GetRLong(PREF_STRN+PREF_MHEIGHT))
  1018.                 r.bottom = r.top + win->vPitch*val;
  1019.             utl_StaggerWindow(&r,1,offset,&corner,GetRLong(PREF_STRN+PREF_NW_DEV));
  1020.             OffsetRect(&r,corner.h-r.left,corner.v-r.top);
  1021.             res = zoomed = False;
  1022.         }
  1023.         SanitizeSize(&r);
  1024.         utl_RestoreWindowPos(win,&r,zoomed,1,FigureZoom,DefPosition);
  1025.     }
  1026.     return(res);
  1027. }
  1028.  
  1029. /************************************************************************
  1030.  * TooLong - complain about a name that's too long
  1031.  ************************************************************************/
  1032. void TooLong(UPtr name)
  1033. {
  1034.     Str63 toolong1,toolong2;
  1035.     MyParamText(GetRString(toolong1,BOX_TOO_LONG1),name,
  1036.                         GetRString(toolong2,BOX_TOO_LONG2),"");
  1037.     ReallyDoAnAlert(OK_ALRT,Note);
  1038. }
  1039.  
  1040. /************************************************************************
  1041.  *
  1042.  ************************************************************************/
  1043. short FindDirLevel(long dirId)
  1044. {
  1045.     short level;
  1046.     short n=GetHandleSize(BoxMap)/sizeof(long);
  1047.     
  1048.     for (level=0;level<n;level++)
  1049.         if ((*BoxMap)[level]==dirId) return(level);
  1050.     
  1051.     return(-1);
  1052. }
  1053.  
  1054. /************************************************************************
  1055.  * BuildBoxCount - build the numbered list of mailboxes (for Find)
  1056.  ************************************************************************/
  1057. void BuildBoxCount(void)
  1058. {
  1059.     if (BoxCount) DisposHandle(BoxCount);
  1060.     BoxCount = NuHandle(0);
  1061.     if (!BoxCount) {WarnUser(MEM_ERR,MemError()); return;}
  1062.     
  1063.     AddBoxCountMenu(GetMHandle(MAILBOX_MENU),MAILBOX_BAR1_ITEM+1,MyDirId);
  1064.     AddBoxCountItem(MAILBOX_IN_ITEM,MyDirId);
  1065.     AddBoxCountItem(MAILBOX_OUT_ITEM,MyDirId);
  1066.     AddBoxCountItem(MAILBOX_TRASH_ITEM,MyDirId);
  1067. }
  1068.  
  1069. /************************************************************************
  1070.  * AddBoxCountMenu - add the contents of a menu to the BoxCount thingy
  1071.  ************************************************************************/
  1072. void AddBoxCountMenu(MenuHandle mh, short item, long dirId)
  1073. {
  1074.     short n=CountMItems(mh);
  1075.     short it;
  1076.  
  1077.     
  1078.     for (;item<=n;item++)
  1079.     {
  1080.         if (HasSubmenu(mh,item))
  1081.         {
  1082.             GetItemMark(mh,item,&it);
  1083.             AddBoxCountMenu(GetMHandle(it),1,(*BoxMap)[it%MAX_BOX_LEVELS]);
  1084.         }
  1085.         else
  1086.             AddBoxCountItem(item,dirId);
  1087.     }
  1088. }
  1089.  
  1090. /************************************************************************
  1091.  * AddBoxCountItem - add a single item to the BoxCount list
  1092.  ************************************************************************/
  1093. void AddBoxCountItem(short item,long dirId)
  1094. {
  1095.     BoxCountElem bce;
  1096.     
  1097.     bce.item = item;
  1098.     bce.dirId = dirId;
  1099.     if (PtrAndHand(&bce,BoxCount,sizeof(bce))) WarnUser(MEM_ERR,MemError());
  1100. }
  1101.  
  1102. /************************************************************************
  1103.  * InsaneTOC - see if a TOC is nuts
  1104.  ************************************************************************/
  1105. Boolean InsaneTOC(TOCHandle tocH)
  1106. {
  1107.     long boxSize;
  1108.     MSumPtr start,stop;
  1109.     short err;
  1110.     Str31 name;
  1111.     
  1112.     PCopy(name,(*tocH)->name);
  1113.  
  1114.     /*
  1115.      * is the toc the right size?
  1116.      */
  1117.     if ((*tocH)->count<0) return(True);
  1118.     if (sizeof(TOCType)+((*tocH)->count?(*tocH)->count-1:0)*sizeof(MSumType)!=
  1119.             GetHandleSize(tocH))
  1120.     {
  1121.         ComposeLogS(LOG_ALRT,nil,"\p%p size mismatch; #%d != %d",name,
  1122.                                     (*tocH)->count,GetHandleSize(tocH));
  1123.         return(True);
  1124.     }
  1125.             
  1126.     /*
  1127.      * figure out how big the mailbox is
  1128.      */
  1129.     if (BoxFOpen(tocH)) return(True);
  1130.     err = GetEOF((*tocH)->refN,&boxSize);
  1131.     BoxFClose(tocH);
  1132.     if (err)
  1133.     {
  1134.         FileSystemError(READ_TOC,name,err);
  1135.         return(True);
  1136.     }
  1137.     
  1138.     /*
  1139.      * check for out of range pointers
  1140.      */
  1141.     for (start=(*tocH)->sums,stop=start+(*tocH)->count;start<stop;start++)
  1142.     {
  1143.         if (start->offset<0 ||start->length<0 ||start->bodyOffset<0 ||
  1144.             start->bodyOffset>start->length ||
  1145.                 start->offset+start->length > boxSize)
  1146.         {
  1147.             ComposeLogS(LOG_ALRT,nil,"\p%p bad sum; o%d b%d l%d s%d",name,
  1148.                 start->offset,start->bodyOffset,start->length,boxSize);
  1149.             return(True);
  1150.         }
  1151.     }
  1152.     
  1153.     /*
  1154.      * everything looks ok
  1155.      */
  1156.     return(False);
  1157. }
  1158.  
  1159. /************************************************************************
  1160.  * WantRebuildTOC - see if the user wants us to remake the toc
  1161.  ************************************************************************/
  1162. Boolean WantRebuildTOC(UPtr boxName)
  1163. {
  1164.     return (AlertStr(REB_TOC_ALRT,Caution,boxName)==TOC_CREATE_NEW);
  1165. }
  1166.  
  1167. /************************************************************************
  1168.  * GetTOCK - grab the K counts for a mailbox
  1169.  ************************************************************************/
  1170. short GetTOCK(TOCHandle tocH,short *usedK, short *totalK)
  1171. {
  1172.     MSumPtr sum;
  1173.     long used=0;
  1174.     short err;
  1175.     HFileInfo info;
  1176.     Str31 name;
  1177.     
  1178.     for (sum=(*tocH)->sums;sum<(*tocH)->sums+(*tocH)->count;sum++)
  1179.         used += sum->length;
  1180.     *usedK = used/1024;
  1181.     PCopy(name,(*tocH)->name);
  1182.     *totalK = (err=HGetFileInfo(MyVRef,(*tocH)->dirId,name,&info)) ?
  1183.                                          0:info.ioFlLgLen/1024;
  1184.     ASSERT(*totalK<4096K);
  1185.     return(err);
  1186. }
  1187.  
  1188. /************************************************************************
  1189.  * CleanseTOC - free a newly-read toc of vestiges of its past life
  1190.  ************************************************************************/
  1191. void CleanseTOC(TOCHandle tocH)
  1192. {
  1193.     MSumPtr sum,limit;
  1194.      /*
  1195.         * unset the selected flags; they might have been saved from last time
  1196.         * unset the messH; it may have been filled the last time
  1197.         */
  1198.     for (sum=(*tocH)->sums,limit=sum+(*tocH)->count; sum<limit; sum++)
  1199.     {
  1200.         sum->messH = 0;
  1201.         sum->selected = False;
  1202.     }
  1203. }
  1204.  
  1205. /************************************************************************
  1206.  * GetTransferParams - get the name & dirid of a mailbox we want to move to
  1207.  ************************************************************************/
  1208. Boolean GetTransferParams(short menu,short item,long *dirId,UPtr name)
  1209. {
  1210.     Boolean folder=False, noxfer=False;
  1211.     long newDirId;
  1212.     Str31 fix;
  1213.     
  1214.     if (*dirId==MyDirId && item==TRANSFER_NEW_ITEM || *dirId!=MyDirId && item==1)
  1215.     {
  1216.         do
  1217.         {
  1218.             if (GetNewMailbox(*dirId,name,&folder,&newDirId,&noxfer))
  1219.             {
  1220.                 BuildBoxMenus();
  1221.                 MBTickle(nil,nil);
  1222.             }
  1223.             else return(False);
  1224.             if (folder) *dirId = newDirId;
  1225.         }
  1226.         while (folder);
  1227.     }
  1228.     else
  1229.     {
  1230.         MyGetItem(GetMHandle(menu),item,name);
  1231.         TrimPrefix(name,GetRString(fix,TRANSFER_PREFIX));
  1232.     }
  1233.     return(!noxfer);
  1234. }
  1235.